
import {createStore, mapActions, mapGetters, mapMutations, mapState, useStore} from "vuex";
import {computed} from "vue";

import demoSon from "@/store/modules/demoSon.js";
import cart from "@/store/modules/cart.js";
import user from "@/store/modules/user.js";

const store = createStore({

    // strict模式开启后，可对在外部修改state的行为进行报错
    // 上线时需关闭strict模式，因为监测要消耗性能
    strict: true,
    state: {
        count: 100,
        f1: 1,
        f2: 2,
        f3: 3,
        f4: 4,
        list: [1,2,3,4,5]
    },
    // 外部虽然可直接修改state，但是为了遵循单向数据流规范，不能随意在外部修改state,否则出错时很难找到修改源，
    // 而是通过 store.commit('ADD_COUNT',param) 提交mutations方法,以及参数，进行修改
    mutations: {
        //外部提交后，由系统携带state,以及payload进行回调
        //只能有1个payload(提交载荷,可无),多个参数可包裹成对象
        f1add1(state,payload) {
            state.f1 += payload;
        },
        f2add1(state,payload) {
            state.f2 += payload;
        },
        f3add1(state) {
            state.f3 += 1;
        },
    },
    // 处理异步操作,但任然通过mutations修改
    // 外部可以通过 store.dispatch('ADD_COUNT',param) 使用actions方法，
    actions: {
        //外部提交后，由系统携带context,以及payload进行回调
        f1add1Async(context,payload){
            //1秒后再执行
            setTimeout(()=>{
                context.commit('f1add1',payload)
            },1000)
        },
        f2add1Async(context,payload){
            setTimeout(()=>{
                context.commit('f2add1',payload)
            },1000)
        },
        f3add1Async(context){
            setTimeout(()=>{
                context.commit('f3add1')
            },1000)
        }
    },
    // 派生状态，类似computed,源变化会重新计算
    getters: {
        filterList(state){
            return state.list.filter(item=>item>2)
        },
        rg1(state){
            return state.f1+100
        },
        rg2(state){
            return state.f2+100
        },
        rg3(state){
            return state.f3+100
        },
        rg4(state){
            return state.f4+100
        },
    },
    //子模块state块会挂到跟root节点的state中，访问store.state.user
    //子模块getters块会挂到跟root节点的getters中，访问store.getters.user
    modules: {
        demoSon,
        cart,
        user
    }
})

export default store;

export function useMapState(obj) {
    const store = useStore()
    // 获取到对应mapper的属性的function
    let stateFns={}
    if (obj.moduleName==null){
        stateFns = mapState(obj.mapper)
    }else {
        stateFns = mapState(obj.moduleName,obj.mapper)
    }

    let stateFnsAfterBindAndComputed = {}
    Object.keys(stateFns).forEach((fnkey) => {
        // storeStateFns[fnkey]拿到每一个key对应的函数
        // .bind()给fn绑定this 才能传给computed
        const fn = stateFns[fnkey].bind({$store: store});
        // 将函数通过computed函数转为ref
        stateFnsAfterBindAndComputed[fnkey] = computed(fn);
    });
    return stateFnsAfterBindAndComputed
}
export function useMapMutations(obj) {
    const store = useStore()

    let commitMutationFns={}
    if (obj.moduleName==null){
        commitMutationFns = mapMutations(obj.mapper)
    }else {
        commitMutationFns = mapMutations(obj.moduleName,obj.mapper)
    }

    let commitMutationFnsAfterBind = {}
    Object.entries(commitMutationFns).forEach(([key, fn]) => {
        let fnAfterBind = fn.bind({$store: store});
        commitMutationFnsAfterBind[key] = fnAfterBind;
    })
    return commitMutationFnsAfterBind
}

export function useMapActions(obj) {
    const store = useStore()

    let dispatchActionsFns={}
    if (obj.moduleName==null){
        dispatchActionsFns = mapActions(obj.mapper)
    }else {
        dispatchActionsFns = mapActions(obj.moduleName,obj.mapper)
    }

    let dispatchActionsFnsAfterBind = {}
    Object.entries(dispatchActionsFns).forEach(([key,fn]) => {
        let fnAfterBind = fn.bind({$store: store});
        dispatchActionsFnsAfterBind[key] = fnAfterBind;
    })
    return dispatchActionsFnsAfterBind
}


export function useMapGetters(obj) {
    const store = useStore()
    let gettersFns={}
    if (obj.moduleName==null){
       gettersFns = mapGetters(obj.mapper);
    }else {
        gettersFns = mapGetters(obj.moduleName,obj.mapper);
    }

    let getters = {}
    Object.entries(gettersFns).forEach(([key,fn]) => {
        getters[key] = computed(fn.bind({$store: store}));
    });
    return getters
}
